﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.IO;

namespace VisualStock.Infrastructure.Models
{
    public class StockHistoricalDataCollection : ObservableCollection<StockHistoricalDataItem>
    {
        public DateTime StartDate { get; private set; }

        public DateTime EndDate { get; private set; }

        public StockHistoricalDataCollection() { }

        public StockHistoricalDataCollection(IEnumerable<StockHistoricalDataItem> list)
        {
            foreach (StockHistoricalDataItem stockHistoricalDataItem in list)
            {
                this.Add(stockHistoricalDataItem);
            }
        }

        public void WriteBinaryDataToFile(FileStream fileStream)
        {
            using (StreamWriter sw = new StreamWriter(fileStream))
            {
                sw.WriteLine(StartDate.ToString());
                sw.WriteLine(EndDate.ToString());
                foreach (StockHistoricalDataItem item in this)
                    sw.WriteLine(item.ConvertDataToString());
                sw.Close();
            }
        }

        public void ReadBinaryDataFromFile(FileStream fileStream)
        {
            using (StreamReader sr = new StreamReader(fileStream))
            {
                // Since the IO error will usually occur in the first two lines while the data is invaild
                // Therefore here just catch  the exception of first two lines
                try
                {
                    StartDate = DateTime.Parse(sr.ReadLine());
                    EndDate = DateTime.Parse(sr.ReadLine());
                }
                catch (IOException)
                {
                    sr.Close();
                    return;
                }
                while (!sr.EndOfStream)
                {
                    StockHistoricalDataItem item = new StockHistoricalDataItem();
                    item.ConvertStringToData(sr.ReadLine());
                    this.Add(item);
                }
                sr.Close();
            }
        }

        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnCollectionChanged(e);

            DateTime date = (e.NewItems[0] as StockHistoricalDataItem).QuoteDate;

            if (this.Count == 1) StartDate = date;
            else if (date.CompareTo(StartDate) < 0) StartDate = date;

            if (this.Count == 1) EndDate = date;
            else if (date.CompareTo(EndDate) > 0) EndDate = date;
        }
    }

    public class StockHistoricalDataItem : IComparable<StockHistoricalDataItem>
    {
        #region Basic Public Property

        /// <summary>
        /// Date of quote, in order to avoid the gap caused by the missing points, please use the RalativeXValue instead of QuoteDate
        /// </summary>
        public DateTime QuoteDate { get; set; }

        /// <summary>
        /// Value of the opening price
        /// </summary>
        public double OpeningPrice { get; set; }

        /// <summary>
        /// Value of the closing price
        /// </summary>
        public double ClosingPrice { get; set; }

        /// <summary>
        /// Value of the highest price
        /// </summary>
        public double HighestPrice { get; set; }

        /// <summary>
        /// Value of the lowest price
        /// </summary>
        public double LowestPrice { get; set; }

        /// <summary>
        /// Value Of the volume
        /// </summary>
        public double Volume { get; set; }

        #endregion

        #region Additional Public Property

        /// <summary>
        /// Return the string format of QuoteDate
        /// </summary>
        public string QuoteDateString { get { return QuoteDate.ToShortDateString(); } }

        /// <summary>
        /// The ralative xvalue for data displaying
        /// </summary>
        public double RelativeXValue { get; set; }
        
        /// <summary>
        /// The relative yvalue for comparison
        /// </summary>
        public double RelativeYValue { get; set; }

        #endregion

        #region IComparable Members

        public int CompareTo(StockHistoricalDataItem other)
        {
            return this.QuoteDate.CompareTo(other.QuoteDate);
        }

        #endregion

        public string ConvertDataToString()
        {
            string str = ClosingPrice.ToString() + "," + HighestPrice.ToString() + "," + LowestPrice.ToString() + "," +
                            OpeningPrice.ToString() + "," + QuoteDate.ToString() + "," + Volume.ToString();
            return str;
        }

        public void ConvertStringToData(string str)
        {
            string[] array = str.Split(',');
            ClosingPrice = double.Parse(array[0]);
            HighestPrice = double.Parse(array[1]);
            LowestPrice = double.Parse(array[2]);
            OpeningPrice = double.Parse(array[3]);
            QuoteDate = DateTime.Parse(array[4]);
            Volume = double.Parse(array[5]);
        }
    }
}
